/* --------------------------------------------------------
 * Copyright (c) Express Scripts, Inc.  All rights reserved.
 * --------------------------------------------------------
 */
package com.aeky.common;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.springframework.util.StringUtils;

/**
 * The Class DateUtils.
 */
public final class DateUtils {

    /** The Constant LOG. */
    // private static final Logger LOG = Logger.getLogger(DateUtils.class);

    /** The Constant MILLISECONDS_OF_ONE_DAY. */
    private static final int MILLISECONDS_OF_ONE_DAY = 1000 * 60 * 60 * 24;

    /** The en locale. */
    private static Locale enLocale = new Locale("en", "US");

    /**
     * Instantiates a new date utils.
     */
    private DateUtils() {
    }

    /**
     * Format used time.
     * 
     * @param ms the ms
     * @return the string
     */
    public static String formatUsedTime(long ms) {
        int ss = 1000;
        int mi = ss * 60;
        int hh = mi * 60;
        int dd = hh * 24;

        long day = ms / dd;
        long hour = (ms - day * dd) / hh;
        long minute = (ms - day * dd - hour * hh) / mi;
        long second = (ms - day * dd - hour * hh - minute * mi) / ss;
        long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;

        String strDay = day < 10 ? "0" + day : "" + day;
        String strHour = hour < 10 ? "0" + hour : "" + hour;
        String strMinute = minute < 10 ? "0" + minute : "" + minute;
        String strSecond = second < 10 ? "0" + second : "" + second;
        String strMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;
        strMilliSecond = milliSecond < 100 ? "0" + strMilliSecond : "" + strMilliSecond;
        return strDay + "��" + strHour + "Сʱ" + strMinute + "��" + strSecond + "��" + strMilliSecond + "����";
    }

    /**
     * Format date.
     * 
     * @param date the date
     * @param pattern the pattern
     * 
     * @return the string
     */
    public static String formatDate(Date date, String pattern) {
        if (date == null) {
            return "";
        }
        if (pattern == null) {
            pattern = "yyyy-MM-dd";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, enLocale);
        return sdf.format(date);
    }

    /**
     * Format date time.
     * 
     * @param date the date
     * 
     * @return the string
     */
    public static String formatDateTime(Date date) {
        return (formatDate(date, "yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * Format date time.
     * 
     * @return the string
     */
    public static String formatDateTime() {
        return (formatDate(now(), "yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * Format date.
     * 
     * @param date the date
     * 
     * @return the string
     */
    public static String formatDate(Date date) {
        return (formatDate(date, "yyyy-MM-dd"));
    }

    /**
     * Format date.
     * 
     * @return the string
     */
    public static String formatDate() {
        return (formatDate(now(), "yyyy-MM-dd"));
    }

    /**
     * Format time.
     * 
     * @param date the date
     * 
     * @return the string
     */
    public static String formatTime(Date date) {
        return (formatDate(date, "HH:mm:ss"));
    }

    /**
     * Format time no colon.
     * 
     * @param date the date
     * 
     * @return the string
     */
    public static String formatTimeNoColon(Date date) {
        return (formatDate(date, "HHmmssSS"));
    }

    /**
     * Format time.
     * 
     * @return the string
     */
    public static String formatTime() {
        return (formatDate(now(), "HH:mm:ss"));
    }

    /**
     * Format full time.
     * 
     * @param date the date
     * 
     * @return the string
     */
    public static String formatFullTime(Date date) {
        return (formatDate(date, "HH:mm:ss SS a"));
    }

    /**
     * Now.
     * 
     * @return the date
     */
    public static Date now() {
        return (new Date());
    }

    /**
     * Parses the datetime.
     * 
     * @param datetime the datetime
     * 
     * @return the date
     * 
     * @throws ParseException the parse exception
     */
    public static Date parseDatetime(String datetime) throws ParseException {
        return parseDate(datetime, "yyyy-MM-dd HH:mm:ss", true);

    }

    /**
     * Specify whether or not date parsing is to be lenient. With lenient
     * parsing, the parser may use heuristics to interpret inputs that do not
     * precisely match this object's format. With strict parsing, inputs must
     * match this object's format. when the date is 2008-13-12 and
     * isLenient=false then throws parase exception when the date is 2008-13-12
     * and isLenient=true then return 2009-01-12.
     * 
     * @param date date
     * @param isLenient isLenient
     * 
     * @return Date
     * 
     * @throws ParseException ParseException
     */
    public static Date parseDate(String date, boolean isLenient) throws ParseException {
        return parseDate(date, "yyyy-MM-dd", isLenient);
    }

    /**
     * Gets the date.
     * 
     * @return the date
     * 
     * @throws ParseException the parse exception
     */
    public static Date getDate() throws ParseException {
        return parseDate(formatDate(), false);
    }

    /**
     * Parses the date.
     * 
     * @param dateString the date string
     * @param pattern the pattern
     * 
     * @return the date
     * 
     * @throws ParseException the parse exception
     */
    public static Date parseDate(String dateString, String pattern) throws ParseException {
        return parseDate(dateString, pattern, true);
    }

    /**
     * Date diff.
     * 
     * @param startDay the start day
     * @param endDay the end day
     * 
     * @return the int
     */
    public static int dateDiff(Date startDay, Date endDay) {
        if (startDay.after(endDay)) {
            Date temp = startDay;
            startDay = endDay;
            endDay = temp;
        }
        long sl = startDay.getTime();
        long el = endDay.getTime();
        long ei = el - sl;
        return (int) (ei / (MILLISECONDS_OF_ONE_DAY));
    }

    /**
     * Date diff.
     * 
     * @param startDay the start day
     * @param endDay the end day
     * 
     * @return the int
     */
    public static int yearDiff(Date startDay, Date endDay) {
        if (startDay.after(endDay)) {
            Date temp = startDay;
            startDay = endDay;
            endDay = temp;
        }
        int sl = getCalendar(startDay).get(Calendar.YEAR);
        int el = getCalendar(endDay).get(Calendar.YEAR);
        return (el - sl) + 1;

    }

    public static Calendar getCalendar(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * Adds the date.
     * 
     * @param date the date
     * @param amount the amount
     * 
     * @return the date
     */
    public static Date addDate(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, amount); // calendar.DATE
        return calendar.getTime();
    }

    /**
     * Adds the month.
     * 
     * @param date the date
     * @param amount the amount
     * 
     * @return the date
     */
    public static Date addMonth(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, amount); // calendar.MONTH
        return calendar.getTime();
    }

    /**
     * Adds the year.
     * 
     * @param date the date
     * @param amount the amount
     * 
     * @return the date
     */
    public static Date addYear(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, amount); // calendar.YEAR
        return calendar.getTime();
    }

    /**
     * Gets the first day of current month.
     * 
     * @return the first day of current month
     */
    public static Date getFirstDayOfCurrentMonth() {
        Calendar calendar = Calendar.getInstance();
        // calendar.setTime(new Date());
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    /**
     * Gets the next day of current month.
     * 
     * @return the next day of current month
     */
    public static Date getNextDayOfCurrentMonth() {
        Calendar calendar = Calendar.getInstance();
        // calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    /**
     * Gets the before day of current day.
     * 
     * @return the before day of current day
     */
    public static Date getBeforeDayOfCurrentDay() {
        Calendar calendar = Calendar.getInstance();
        // calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        return calendar.getTime();
    }

    /**
     * Gets the first day of current year.
     * 
     * @return the first day of current year
     */
    public static Date getFirstDayOfCurrentYear() {
        Calendar calendar = Calendar.getInstance();
        // calendar.setTime(new Date());
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    // 1998-12-01
    /**
     * Gets the date for noc.
     * 
     * @return the date for noc
     */
    public static Date getDateForNOC() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, 1998);
        calendar.set(Calendar.MONTH, 11);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    /**
     * Gets the current date of last year.
     * 
     * @return the current date of last year
     */
    public static Date getCurrentDateOfLastYear() {
        Calendar calendar = Calendar.getInstance();
        // calendar.setTime(new Date());
        calendar.add(Calendar.YEAR, -1);
        return calendar.getTime();
    }

    /**
     * Gets the biggest date.
     * 
     * @return the biggest date
     */
    public static Date getBiggestDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(9999, 11, 31);
        return calendar.getTime();
    }

    /**
     * Parses the date.
     * 
     * @param date the date
     * 
     * @return the date
     * 
     * @throws ParseException the parse exception
     */
    public static Date parseDate(String date) {
        try {
            return parseDate(date, false);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * Before today.
     * 
     * @param date the date
     * 
     * @return true, if successful
     */
    public static boolean beforeToday(Date date) {
        Date currentDate = DateUtils.parseDate(formatDate(new Date()));
        return date.before(currentDate);
    }

    /**
     * After today.
     * 
     * @param date the date
     * 
     * @return true, if successful
     */
    public static boolean afterToday(Date date) {
        Date currentDate = null;
        currentDate = DateUtils.parseDate(formatDate(new Date()));
        return date.after(currentDate);
    }

    /**
     * Parses the date.
     * 
     * @param dateString the date string
     * @param pattern the pattern
     * @param isLenient the is lenient
     * 
     * @return the date
     * 
     * @throws ParseException the parse exception
     */
    public static Date parseDate(String dateString, String pattern, boolean isLenient) throws ParseException {
        if (!StringUtils.hasText(dateString)) {
            return null;
        }
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        formatter.setLenient(false);
        Date resultDate = null;
        resultDate = formatter.parse(dateString);
        return resultDate;

    }

    /**
     * Gets the current time stamp.
     * 
     * @return the current time stamp
     */
    public static Timestamp getCurrentTimeStamp() {
        return new Timestamp((new Date()).getTime());
    }

    /**
     * Gets the term date.
     * 
     * @param date the date
     * @return the term date
     */
    public static Date getTermDate(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    public static Date getEffDate(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    public static void main(String[] args) {
        System.out.println(formatDate(getEffDate(new Date()), "yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * Gets the day.
     * 
     * @param date the date
     * 
     * @return the day
     * @throws ParseException
     */
    public static Date getDay(Date date) {
        return parseDate(formatDate(date));
        // Calendar calendar =
        // Calendar.getInstance(enLocale);
        // calendar.setTime(date);
        // calendar.set(Calendar.HOUR_OF_DAY, 0);
        // calendar.set(Calendar.MINUTE, 0);
        // calendar.set(Calendar.SECOND, 0);
        // calendar.set(Calendar.MILLISECOND, 0);
        // return calendar.getTime();
    }

    /*
     * public static void main(String[] arg) throws ParseException { // Date
     * date = new Date(); // String TimeZoneIds[] = TimeZone.getAvailableIDs();
     * // for(int i = 0; i < TimeZoneIds.length; i++){ // TimeZone tz =
     * TimeZone.getTimeZone(TimeZoneIds[i]); // String tzName =
     * tz.getDisplayName(tz.inDaylightTime(date), // TimeZone.LONG); //
     * System.out.print(TimeZoneIds[i] + ":   "); // // Get the number of hours
     * from GMT // int rawOffset = tz.getRawOffset(); // int hour = rawOffset /
     * (60*60*1000); // int minute = Math.abs(rawOffset / (60*1000)) % 60; //
     * System.out.println(tzName + " " + hour + ":" + minute); // } Calendar
     * calendar = Calendar.getInstance(TimeZone.getTimeZone("US/Eastern"));
     * calendar.setTime(new Date()); calendar.set(Calendar.HOUR_OF_DAY, 0);
     * calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0);
     * calendar.set(Calendar.MILLISECOND, 0);
     * System.out.println(DateUtils.formatDate(DateUtils.addDate(getDay(new
     * Date()), 1), "yyyy-MM-dd HH:mm:ss")); // DateTimeFormat format =
     * DateTimeFormat.getShortDateFormat(); }
     */

    public static XMLGregorianCalendar convertDateToXMLGregorianCalendar(Date date) {
        if (date == null) {
            return null;
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        XMLGregorianCalendar gc = null;
        try {
            gc = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return gc;
    }
}
